package com.gzyz.cheetah.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.Db;
import com.gzyz.cheetah.entity.dto.DocumentDTO;
import com.gzyz.cheetah.entity.dto.PageDTO;
import com.gzyz.cheetah.entity.pagerequest.DocumentPageRequest;
import com.gzyz.cheetah.entity.table.Document;
import com.gzyz.cheetah.entity.table.Keyword;
import com.gzyz.cheetah.entity.table.User;
import com.gzyz.cheetah.enums.entityproperty.DocumentCommentStatus;
import com.gzyz.cheetah.enums.entityproperty.DocumentIsPublic;
import com.gzyz.cheetah.enums.entityproperty.DocumentStatus;
import com.gzyz.cheetah.exception.DocumentServiceException;
import com.gzyz.cheetah.mapper.DocumentMapper;
import com.gzyz.cheetah.service.IDocumentService;
import com.gzyz.cheetah.util.MinioUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * <p>
 * 文档 服务实现类
 * </p>
 *
 * @author xclhove
 * @since 2023-11-06
 */
@Service
@RequiredArgsConstructor
public class DocumentServiceImpl extends ServiceImpl<DocumentMapper, Document> implements IDocumentService {
    private final MinioUtil minioUtil;
    private final DocumentMapper documentMapper;
    @Value("${cheetah.document.support-type}")
    private String documentSupportType;
    
    @Override
    public Document uploadDocument(Integer userId, MultipartFile uploadDocument) {
        if (uploadDocument == null) {
            throw new DocumentServiceException("文件不能为空!");
        }
        String fileName = uploadDocument.getOriginalFilename();
        if (!fileName.matches(documentSupportType)) {
            throw new DocumentServiceException("不支持该文件格式！");
        }
        User user = Db.getById(userId, User.class);
        Long currentStorageSize = documentMapper.countUserDocumentSize(userId);
        if (currentStorageSize == null) currentStorageSize = 0L;
        if ((currentStorageSize + uploadDocument.getSize()) > user.getStorageSize()) {
            throw new DocumentServiceException("存储空间不足");
        }
        String documentPath = minioUtil.upload(uploadDocument);
        Document document = new Document();
        document.setFilePath(documentPath);
        document.setUserId(userId);
        document.setTitle(uploadDocument.getOriginalFilename());
        document.setSize(uploadDocument.getSize());
        List<Keyword> keywords = new ArrayList<>();
        keywords.add(new Keyword(1, uploadDocument.getOriginalFilename()));
        document.setKeywords(keywords);
        this.save(document);
        return document;
    }
    
    @Override
    public boolean deleteDocumentById(Integer userId, Integer documentId) {
        LambdaQueryWrapper<Document> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Document::getId, documentId);
        Document document = this.getOne(queryWrapper);
        if (document == null) {
            throw new DocumentServiceException("文档不存在！");
        }
        if (!Objects.equals(document.getUserId(), userId)) {
            throw new DocumentServiceException("文档不属于你！");
        }
        if (document.getStatus() == DocumentStatus.FROZEN) {
            throw new DocumentServiceException("文档已被冻结，无法删除！");
        }
        boolean deleteSuccess = this.remove(queryWrapper);
        boolean deleteFileSuccess = minioUtil.deleteFileByFileName(document.getFilePath());
        if (!deleteSuccess) {
            throw new DocumentServiceException("删除失败，请重试！");
        }
        return deleteSuccess;
    }
    
    @Override
    @Transactional
    public boolean deleteDocumentsByIds(Integer userId, List<Integer> documentIds) {
        LambdaQueryWrapper<Document> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.select(Document::getId)
                .eq(Document::getUserId, userId)
                .eq(Document::getStatus, DocumentStatus.NORMAL)
                .in(Document::getId, documentIds);
        List<Document> documents = this.list(queryWrapper);
        boolean deleteSuccess = this.removeByIds(documents);
        if (!deleteSuccess) {
            throw new DocumentServiceException("删除失败！");
        }
        return true;
    }
    
    @Override
    public boolean updateDocument(Document document) {
        LambdaQueryWrapper<Document> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Document::getId, document.getId())
                .eq(Document::getUserId, document.getUserId());
        Document oldDocument = this.getOne(queryWrapper);
        if (oldDocument == null) throw new DocumentServiceException("文档不存在或文档不属于你！");
        if (oldDocument.getStatus() == DocumentStatus.FROZEN) throw new DocumentServiceException("文档已被冻结，无法修改！");
        oldDocument.setUpdateTime(LocalDateTime.now());
        oldDocument.setKeywords(document.getKeywords());
        oldDocument.setTitle(document.getTitle());
        oldDocument.setIsPublic(document.getIsPublic());
        boolean updateSuccess = this.updateById(oldDocument);
        if (!updateSuccess) throw new DocumentServiceException("保存失败，请重试！");
        return true;
    }
    
    @Override
    public Document getOneDocumentById(Integer userId, Integer documentId) {
        Document document = this.getById(documentId);
        if (document == null) throw new DocumentServiceException("文档不存在！");
        if (document.getStatus() == DocumentStatus.FROZEN &&
                !Objects.equals(document.getUserId(), userId)) {
            throw new DocumentServiceException("该文档已被冻结！");
        }
        if (document.getIsPublic() == DocumentIsPublic.NO &&
                !Objects.equals(document.getUserId(), userId)) {
            throw new DocumentServiceException("无法查看私有文档！");
        }
        return document;
    }
    
    @Override
    public PageDTO<Document> pageUserDocuments(Integer userId, DocumentPageRequest pageRequest) {
        boolean showPrivate = false;
        PageDTO<Document> userDocuments = pageUserDocuments(userId, pageRequest, showPrivate);
        return userDocuments;
    }
    
    @Override
    public PageDTO<Document> pageUserDocuments(Integer userId, DocumentPageRequest pageRequest, boolean showPrivate) {
        String searchTitle = pageRequest.getSearchTitle();
        if (StrUtil.isBlank(searchTitle)) searchTitle = "";
        String searchKeyword = pageRequest.getSearchKeyword();
        if (StrUtil.isBlank(searchKeyword)) searchKeyword = "";
        String finalSearchKeyword = searchKeyword;
        LambdaQueryWrapper<Document> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Document::getUserId, userId)
                .eq(!showPrivate, Document::getIsPublic, DocumentIsPublic.YES)
                .like(Document::getTitle, searchTitle)
                .and(qw -> qw.like(Document::getKeywords, finalSearchKeyword));
        Page<Document> page = new Page<>(pageRequest.getPageNo(), pageRequest.getPageSize());
        Page<Document> pageResult = this.page(page, queryWrapper);
        List<Document> userDocuments = pageResult.getRecords();
        LambdaQueryWrapper<Document> lambdaQueryWrapper = new LambdaQueryWrapper<Document>();
        lambdaQueryWrapper.eq(!showPrivate,Document::getIsPublic,DocumentIsPublic.YES)
                .eq(Document::getUserId, userId);
        int total = this.list(lambdaQueryWrapper).size();
        PageDTO<Document> pageDTO = new PageDTO<>();
        pageDTO.setDataLists(userDocuments);
        pageDTO.setTotal(total);
        return pageDTO;
    }
    
    @Override
    public boolean freezeDocumentById(Integer documentId) {
        LambdaUpdateWrapper<Document> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Document::getId, documentId)
                .set(Document::getStatus, DocumentStatus.FROZEN)
                .set(Document::getUpdateTime, LocalDateTime.now());
        boolean updateSuccess = this.update(updateWrapper);
        if (!updateSuccess) throw new DocumentServiceException("冻结失败，请重试！");
        return updateSuccess;
    }
    
    @Override
    public boolean unFreezeDocumentById(Integer documentId) {
        LambdaUpdateWrapper<Document> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Document::getId, documentId)
                .set(Document::getStatus, DocumentStatus.NORMAL)
                .set(Document::getUpdateTime, LocalDateTime.now());
        boolean updateSuccess = this.update(updateWrapper);
        if (!updateSuccess) throw new DocumentServiceException("解冻失败，请重试！");
        return updateSuccess;
    }
    
    @Override
    public boolean freezeUserDocuments(Integer userId) {
        LambdaQueryWrapper<Document> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Document::getUserId, userId).select(Document::getId);
        List<Document> userDocuments = this.list(queryWrapper);
        if (userDocuments.isEmpty()) {
            throw new DocumentServiceException("该用户未上传文档！");
        }
        LambdaUpdateWrapper<Document> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Document::getUserId, userId)
                .set(Document::getStatus, DocumentStatus.FROZEN)
                .set(Document::getUpdateTime, LocalDateTime.now());
        boolean updateSuccess = this.update(updateWrapper);
        if (!updateSuccess) throw new DocumentServiceException("冻结失败，请重试！");
        return updateSuccess;
    }
    
    @Override
    public boolean unFreezeUserDocuments(Integer userId) {
        LambdaQueryWrapper<Document> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Document::getUserId, userId).select(Document::getId);
        List<Document> userDocuments = this.list(queryWrapper);
        if (userDocuments.isEmpty()) {
            throw new DocumentServiceException("该用户未上传文档！");
        }
        LambdaUpdateWrapper<Document> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Document::getUserId, userId)
                .set(Document::getStatus, DocumentStatus.NORMAL)
                .set(Document::getUpdateTime, LocalDateTime.now());
        boolean updateSuccess = this.update(updateWrapper);
        if (!updateSuccess) throw new DocumentServiceException("所有文档已被冻结，无需再次冻结！");
        return updateSuccess;
    }
    
    @Override
    public void download(HttpServletResponse response, Integer downloadUserId, Integer documentId) {
        Document document = this.getById(documentId);
        if (document == null) {
            throw new DocumentServiceException("该文档不存在！");
        }
        if ((document.getIsPublic() == DocumentIsPublic.NO) && !Objects.equals(document.getUserId(), downloadUserId)) {
            throw new DocumentServiceException("你无法下载或查看私有文档！");
        }
        if ((document.getUserId() != downloadUserId) && (document.getStatus() == DocumentStatus.FROZEN)) {
            throw new DocumentServiceException("该文档已被冻结，无法下载!");
        }
        minioUtil.downloadFile(document.getFilePath(), document.getTitle(), response);
    }
    
    @Override
    public PageDTO<DocumentDTO> searchDocuments(DocumentPageRequest pageRequest) {
        String searchUser = pageRequest.getSearchUser();
        if (StrUtil.isBlank(searchUser)) searchUser = "";
        String searchTitle = pageRequest.getSearchTitle();
        if (StrUtil.isBlank(searchTitle)) searchUser = "";
        String searchKeyword = pageRequest.getSearchKeyword();
        if (StrUtil.isBlank(searchKeyword)) searchUser = "";
        Integer total = documentMapper.countSearchDocuments(pageRequest);
        Integer pageNo = pageRequest.getPageNo();
        Integer pageSize = pageRequest.getPageSize();
        Integer totalPage = (total / pageSize) ;
        if ((total % pageSize) > 0) totalPage++;
        if (totalPage < 1) totalPage = 1;
        if (pageNo > totalPage) pageNo = totalPage;
        pageRequest.setPageNo((pageNo - 1) * pageSize);
        List<DocumentDTO> documentDTOS = documentMapper.searchDocuments(pageRequest);
        PageDTO<DocumentDTO> pageDTO = new PageDTO<>(total, documentDTOS);
        return pageDTO;
    }
    
    @Override
    public PageDTO<Document> pageDocuments(String searchTitle, Integer pageNumber, Integer pageSize) {
        if (StrUtil.isBlank(searchTitle)) searchTitle = "";
        LambdaQueryWrapper<Document> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(Document::getTitle, searchTitle);
        Page<Document> page = new Page<>(pageNumber, pageSize);
        List<Document> documents = this.page(page, queryWrapper).getRecords();
        int total = this.list(queryWrapper).size();
        PageDTO<Document> documentPageDTO = new PageDTO<>(total, documents);
        return documentPageDTO;
    }
    
    @Override
    public void changeCommentStatus(Integer documentId) {
        Document document = this.getById(documentId);
        if (document == null) {
            throw new DocumentServiceException("文档不存在！");
        }
        if (document.getCommentStatus() == DocumentCommentStatus.close) {
            document.setCommentStatus(DocumentCommentStatus.open);
        } else {
            document.setCommentStatus(DocumentCommentStatus.close);
        }
        this.updateById(document);
    }
}
